package com.sky.aop;

import com.sky.Annoation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.validation.constraints.Past;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component//交给ioc管理
@Slf4j
public class AutoFillAspect {

    /*
    * 切入点
    *
   *：匹配任意返回值类型。
com.sky.mapper.*：匹配 com.sky.mapper 包下的所有类。
*：匹配所有方法名。
(..)：匹配任意参数（数量和类型不限）
    * */

    //通配符
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.Annoation.AutoFill)")
    public void pointCut() {}
    //前置通知,再插入或更新前执行
    //括号里是切入点
    @Before("pointCut()")
    //连接点（下面括号里）
    public void Before(JoinPoint joinPoint) throws InvocationTargetException, IllegalAccessException {
        log.info("Before method invoked.");
        //获取注解类型
        MethodSignature Signature  = (MethodSignature) joinPoint.getSignature();
        AutoFill autoFill= Signature.getMethod().getAnnotation(AutoFill.class);
        OperationType operationType= autoFill.value();
        Object[] args = joinPoint.getArgs();//获取所有参数，约定第一个参数是实体

        if(args==null || args.length==0){
            return;
        }

        //不知道具体类型 用Object来定义实体
        Object arg = args[0];


        //数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId= BaseContext.getCurrentId();
        //统一赋值
        if(operationType==OperationType.INSERT){
           try {
              Method setCreatTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
              Method setUpdatTime = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
              Method setCreateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
              Method setUpdateUser = arg.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
              setCreatTime.invoke(arg,now);
              setUpdatTime.invoke(arg,now);
              setCreateUser.invoke(arg,currentId);
              setUpdateUser.invoke(arg,currentId);
           } catch (NoSuchMethodException e) {
               throw new RuntimeException(e);
           }
           }else if(operationType==OperationType.UPDATE){
            try {
                Method setUpdatTime = arg.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
                Method setUpdateUser = arg.getClass().getDeclaredMethod("setUpdateUser", Long.class);
                setUpdatTime.invoke(arg,now);
                setUpdateUser.invoke(arg,currentId);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException(e);
            }

        }
        }


    }






